

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Han Qiu">
  <meta name="keywords" content="">
  
    <meta name="description" content="一、常用 Composition API1. setupsetup 是 Vue3.0 中一个新的配置项，值为一个函数，是所有 Composition API 的入口 两个注意点：  1.setup 执行的时机：在 beforeCreate 之前执行一次，this 是 undefined 2.setup 的参数： props：值为对象，包含组件外部传递过来，且组件内部声明接收了的属性 content">
<meta property="og:type" content="article">
<meta property="og:title" content="vue3新特性">
<meta property="og:url" content="http://example.com/2022/03/03/vue3%E6%96%B0%E7%89%B9%E6%80%A7/index.html">
<meta property="og:site_name" content="寒秋の博客">
<meta property="og:description" content="一、常用 Composition API1. setupsetup 是 Vue3.0 中一个新的配置项，值为一个函数，是所有 Composition API 的入口 两个注意点：  1.setup 执行的时机：在 beforeCreate 之前执行一次，this 是 undefined 2.setup 的参数： props：值为对象，包含组件外部传递过来，且组件内部声明接收了的属性 content">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png">
<meta property="og:image" content="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue2%E5%92%8Cvue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90%E5%AF%B9%E6%AF%94.png">
<meta property="og:image" content="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/provide%E5%92%8Cinject.png">
<meta property="og:image" content="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue2%E5%92%8Cvue3%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%E9%92%A9%E5%AD%90%E5%AF%B9%E6%AF%94.png">
<meta property="article:published_time" content="2022-03-03T03:53:47.000Z">
<meta property="article:modified_time" content="2022-03-09T02:00:36.071Z">
<meta property="article:author" content="Han Qiu">
<meta property="article:tag" content="vue3">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png">
  
  
  <title>vue3新特性 - 寒秋の博客</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hint.css@2/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.8.14","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 6.0.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>blogs</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="vue3新特性">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-03-03 11:53" pubdate>
        2022年3月3日 中午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      13k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      108 分钟
    </span>
  

  
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">vue3新特性</h1>
            
            <div class="markdown-body">
              <h3 id="一、常用-Composition-API"><a href="#一、常用-Composition-API" class="headerlink" title="一、常用 Composition API"></a>一、常用 Composition API</h3><h4 id="1-setup"><a href="#1-setup" class="headerlink" title="1. setup"></a>1. setup</h4><p>setup 是 Vue3.0 中一个新的配置项，值为一个函数，是所有 Composition API 的入口</p>
<p><strong>两个注意点</strong>：</p>
<ul>
<li>1.setup 执行的时机：在 beforeCreate 之前执行一次，this 是 undefined</li>
<li>2.setup 的参数：<ul>
<li>props：值为对象，包含组件外部传递过来，且组件内部声明接收了的属性</li>
<li>content：上下文对象<ul>
<li>attrs：值为对象，包含组件外部传递过来，但没有在 props 配置中声明的属性，相当于 <code>this.$attrs</code></li>
<li>slots：收到的插槽内容，相当于 <code>this.$slots</code></li>
<li>emit：分发自定义事件的函数，相当于 <code>this.$emit</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="2-ref-和-reactive"><a href="#2-ref-和-reactive" class="headerlink" title="2. ref 和 reactive"></a>2. ref 和 reactive</h4><h5 id="2-1-ref-和-reactive-使用"><a href="#2-1-ref-和-reactive-使用" class="headerlink" title="2.1 ref 和 reactive 使用"></a>2.1 ref 和 reactive 使用</h5><ul>
<li>ref 用于定义一个响应式的数据<ul>
<li>定义基本数据类型：响应式是靠 Object.defineProperty() 的 get 和 set 完成的</li>
<li>定义对象数据类型：内部实际使用 reactive 函数</li>
</ul>
</li>
<li>reactive 用于定义一个<strong>对象类型</strong>的响应式数据</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>num: &#123;&#123; num &#125;&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>obj.name: &#123;&#123; obj.name &#125;&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>obj.age: &#123;&#123; obj.age &#125;&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span><br></code></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">import</span> &#123; ref, reactive &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;vue&#x27;</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;<br>  <span class="hljs-function"><span class="hljs-title">setup</span>(<span class="hljs-params"></span>)</span> &#123;<br>    <span class="hljs-keyword">const</span> num = ref(<span class="hljs-number">1</span>)<br>    <span class="hljs-keyword">const</span> obj = reactive(&#123;<br>      <span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;张三&#x27;</span>,<br>      <span class="hljs-attr">age</span>: <span class="hljs-number">18</span><br>    &#125;)<br>    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> &#123;<br>      num.value ++;<br>      obj.age ++;<br>    &#125;, <span class="hljs-number">3000</span>);<br>    <span class="hljs-keyword">return</span> &#123;<br>      num,<br>      obj<br>    &#125;<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h5 id="2-2-ref-与-reactive-对比"><a href="#2-2-ref-与-reactive-对比" class="headerlink" title="2.2 ref 与 reactive 对比"></a>2.2 ref 与 reactive 对比</h5><ul>
<li>从定义数据角度对比：<ul>
<li>ref用来定义：基本类型数据。</li>
<li>reactive用来定义：对象（或数组）类型数据。</li>
<li>备注：ref也可以用来定义对象（或数组）类型数据, 它内部会自动通过reactive转为代理对象。</li>
</ul>
</li>
<li>从原理角度对比：<ul>
<li>ref通过Object.defineProperty()的get与set来实现响应式（数据劫持）。</li>
<li>reactive通过使用Proxy来实现响应式（数据劫持）, 并通过Reflect操作源对象内部的数据。</li>
</ul>
</li>
<li>从使用角度对比：<ul>
<li>ref定义的数据：操作数据需要.value，读取数据时模板中直接读取不需要.value。</li>
<li>reactive定义的数据：操作数据与读取数据：均不需要.value。</li>
</ul>
</li>
</ul>
<h5 id="2-3-vue2-和-vue3-响应式对比"><a href="#2-3-vue2-和-vue3-响应式对比" class="headerlink" title="2.3 vue2 和 vue3 响应式对比"></a>2.3 vue2 和 vue3 响应式对比</h5><ul>
<li>vue2实现原理：<ul>
<li>对象类型：通过 Object.defineProperty() 对属性的读取、修改进行拦截（数据劫持）</li>
<li>数组类型：通过重写更新数组的一系列方法来实现拦截（对数组的变更方法进行了包裹）</li>
<li>为什么数组类型不通过 Object.defineProperty() 对数组属性进行监听？<a target="_blank" rel="noopener" href="https://github.com/vuejs/vue/issues/8562">（Object.defineProperty 可以对数组元素监听，但是性能代价和获得的用户体验收益不成正比）</a></li>
</ul>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-built_in">Object</span>.defineProperty(data, <span class="hljs-string">&#x27;count&#x27;</span>, &#123;<br>    get () &#123;&#125;, <br>    set () &#123;&#125;<br>&#125;)<br></code></pre></td></tr></table></figure>

<ul>
<li>vue3实现原理：<ul>
<li>通过 Proxy（代理）：拦截对象中任意属性的变化，包括属性值的读写、属性的添加、属性的删除等</li>
<li>通过 Reflect（反射）：对源对象的属性进行操作</li>
</ul>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> proxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(data, &#123;<br>	<span class="hljs-comment">// 拦截读取属性值</span><br>    get (target, prop) &#123;<br>    	<span class="hljs-keyword">return</span> <span class="hljs-built_in">Reflect</span>.get(target, prop)<br>    &#125;,<br>    <span class="hljs-comment">// 拦截设置属性值或添加新属性</span><br>    set (target, prop, value) &#123;<br>    	<span class="hljs-keyword">return</span> <span class="hljs-built_in">Reflect</span>.set(target, prop, value)<br>    &#125;,<br>    <span class="hljs-comment">// 拦截删除属性</span><br>    deleteProperty (target, prop) &#123;<br>    	<span class="hljs-keyword">return</span> <span class="hljs-built_in">Reflect</span>.deleteProperty(target, prop)<br>    &#125;<br>&#125;)<br>proxy.name = <span class="hljs-string">&#x27;tom&#x27;</span><br></code></pre></td></tr></table></figure>

<h4 id="3-计算属性与监视"><a href="#3-计算属性与监视" class="headerlink" title="3. 计算属性与监视"></a>3. 计算属性与监视</h4><h5 id="3-1-computed"><a href="#3-1-computed" class="headerlink" title="3.1 computed"></a>3.1 computed</h5><p>与 vue2 中 computed 配置功能一致</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">import</span> &#123; computed, reactive &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;vue&#x27;</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;<br>  <span class="hljs-function"><span class="hljs-title">setup</span>(<span class="hljs-params"></span>)</span> &#123;<br>    <span class="hljs-keyword">const</span> person = reactive&#123;<br>      <span class="hljs-attr">firstName</span>: <span class="hljs-string">&#x27;张&#x27;</span>,<br>      <span class="hljs-attr">lastName</span>: <span class="hljs-string">&#x27;三&#x27;</span><br>    &#125;<br>    <span class="hljs-comment">// const fullName = computed(() =&gt; &#123;</span><br>    <span class="hljs-comment">//   return `$&#123;person.firstName&#125;-$&#123;person.lastName&#125;`</span><br>    <span class="hljs-comment">// &#125;)</span><br>    <span class="hljs-keyword">const</span> fullName = computed(&#123;<br>      <span class="hljs-function"><span class="hljs-title">get</span>(<span class="hljs-params"></span>)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">$&#123;person.firstName&#125;</span>-<span class="hljs-subst">$&#123;person.lastName&#125;</span>`</span><br>      &#125;,<br>      <span class="hljs-function"><span class="hljs-title">set</span>(<span class="hljs-params">value</span>)</span> &#123;<br>        <span class="hljs-keyword">const</span> nameArr = value.split(<span class="hljs-string">&#x27;-&#x27;</span>)<br>        person.firstName = nameArr[<span class="hljs-number">0</span>]<br>        person.lastName = nameArr[<span class="hljs-number">1</span>]<br>      &#125;<br>    &#125;)<br>    <span class="hljs-keyword">return</span> &#123;<br>      person,<br>      fullName<br>    &#125;<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h5 id="3-2-watch"><a href="#3-2-watch" class="headerlink" title="3.2 watch"></a>3.2 watch</h5><p>与 vue2 中 watch 配置功能一致</p>
<p><strong>注意点：</strong></p>
<ol>
<li>监视reactive定义的响应式数据时：oldValue无法正确获取、强制开启了深度监视（deep配置失效）。</li>
<li>监视reactive定义的响应式数据中某个属性时：deep配置有效。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">//情况一：监视ref定义的响应式数据</span><br>watch(sum, <span class="hljs-function">(<span class="hljs-params">newValue, oldValue</span>)=&gt;</span>&#123;<br>	<span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;sum变化了&#x27;</span>, newValue, oldValue)<br>&#125;, &#123;<span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span>&#125;)<br><br><span class="hljs-comment">//情况二：监视多个ref定义的响应式数据</span><br>watch([sum, msg], <span class="hljs-function">(<span class="hljs-params">newValue, oldValue</span>)=&gt;</span>&#123;<br>	<span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;sum或msg变化了&#x27;</span>, newValue, oldValue)<br>&#125;) <br><br><span class="hljs-comment">/* 情况三：监视reactive定义的响应式数据</span><br><span class="hljs-comment">			若watch监视的是reactive定义的响应式数据，则无法正确获得oldValue！！</span><br><span class="hljs-comment">			若watch监视的是reactive定义的响应式数据，则强制开启了深度监视 </span><br><span class="hljs-comment">*/</span><br>watch(person, <span class="hljs-function">(<span class="hljs-params">newValue, oldValue</span>)=&gt;</span>&#123;<br>	<span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;person变化了&#x27;</span>, newValue, oldValue)<br>&#125;, &#123;<span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">deep</span>: <span class="hljs-literal">false</span>&#125;) <span class="hljs-comment">//此处的deep配置不再奏效</span><br><br><span class="hljs-comment">//情况四：监视reactive定义的响应式数据中的某个属性</span><br>watch(<span class="hljs-function">()=&gt;</span>person.job, <span class="hljs-function">(<span class="hljs-params">newValue, oldValue</span>)=&gt;</span>&#123;<br>	<span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;person的job变化了&#x27;</span>, newValue, oldValue)<br>&#125;, &#123;<span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">deep</span>: <span class="hljs-literal">true</span>&#125;) <br><br><span class="hljs-comment">//情况五：监视reactive定义的响应式数据中的某些属性</span><br>watch([<span class="hljs-function">()=&gt;</span>person.job, <span class="hljs-function">()=&gt;</span>person.name], <span class="hljs-function">(<span class="hljs-params">newValue, oldValue</span>)=&gt;</span>&#123;<br>	<span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;person的job变化了&#x27;</span>, newValue, oldValue)<br>&#125;, &#123;<span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">deep</span>: <span class="hljs-literal">true</span>&#125;)<br><br><span class="hljs-comment">//特殊情况</span><br>watch(<span class="hljs-function">()=&gt;</span>person.job, <span class="hljs-function">(<span class="hljs-params">newValue, oldValue</span>)=&gt;</span>&#123;<br>    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;person的job变化了&#x27;</span>, newValue, oldValue)<br>&#125;, &#123;<span class="hljs-attr">deep</span>: <span class="hljs-literal">true</span>&#125;) <span class="hljs-comment">//此处由于监视的是reactive素定义的对象中的某个属性，所以deep配置有效</span><br></code></pre></td></tr></table></figure>

<h5 id="3-3-watchEffect"><a href="#3-3-watchEffect" class="headerlink" title="3.3 watchEffect"></a>3.3 watchEffect</h5><ul>
<li>watchEffect 与 watch 区别：watch 既要指明监视的属性，也要指明监视的回调。而 watchEffect 不用指明监视哪个属性，监视的回调中用到哪个属性，那就监视哪个属性。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// watchEffect所指定的回调中用到的数据只要发生变化，则直接重新执行回调。</span><br>watchEffect(<span class="hljs-function">()=&gt;</span>&#123;<br>    <span class="hljs-keyword">const</span> x1 = sum.value<br>    <span class="hljs-keyword">const</span> x2 = person.age<br>    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;watchEffect配置的回调执行了&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure>

<h4 id="4-生命周期"><a href="#4-生命周期" class="headerlink" title="4. 生命周期"></a>4. 生命周期</h4><p><img src="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png" srcset="/img/loading.gif" lazyload alt="vue3生命周期"></p>
<ul>
<li><p>vue3 中可以继续使用 vue2 中的生命周期钩子，但是有两个被更名</p>
<ul>
<li>beforeDestroy 更名为 beforeUnmount</li>
<li>destroyed 更名为 unmounted</li>
</ul>
</li>
<li><p>vue3 也提供了 Composition API 形式的生命周期钩子，与 vue2 中钩子对应关系如下：</p>
<ul>
<li>beforeCreate ===&gt; setup</li>
<li>created =======&gt; setup</li>
<li>beforeMount ===&gt; onBeforeMount</li>
<li>mounted ======&gt; onMounted</li>
<li>beforeUpdate ===&gt; onBeforeUpdate</li>
<li>updated =======&gt; onUpdated</li>
<li>beforeDestroy ==&gt; onBeforeUnmount</li>
<li>destroyed =====&gt; onUnmounted</li>
<li>onRenderTracked（新增，调试用）</li>
<li>onRenderTriggered（新增，调试用）</li>
</ul>
</li>
</ul>
<p><img src="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue2%E5%92%8Cvue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90%E5%AF%B9%E6%AF%94.png" srcset="/img/loading.gif" lazyload alt="vue2和vue3生命周期钩子对比"></p>
<h4 id="5-自定义-hook-函数"><a href="#5-自定义-hook-函数" class="headerlink" title="5. 自定义 hook 函数"></a>5. 自定义 hook 函数</h4><ul>
<li><p>hook 本质是使用 vue3 的组合 API 封装的可复用的功能函数</p>
</li>
<li><p>示例1：收集用户鼠标点击的页面坐标</p>
</li>
</ul>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">import</span> &#123; ref, onMounted, onUnmounted &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;vue&#x27;</span><br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useMousePosition</span> (<span class="hljs-params"></span>) </span>&#123;<br>  <span class="hljs-comment">// 初始化坐标数据</span><br>  <span class="hljs-keyword">const</span> x = ref(-<span class="hljs-number">1</span>)<br>  <span class="hljs-keyword">const</span> y = ref(-<span class="hljs-number">1</span>)<br><br>  <span class="hljs-comment">// 用于收集点击事件坐标的函数</span><br>  <span class="hljs-keyword">const</span> updatePosition = <span class="hljs-function">(<span class="hljs-params">e: MouseEvent</span>) =&gt;</span> &#123;<br>    x.value = e.pageX<br>    y.value = e.pageY<br>  &#125;<br><br>  <span class="hljs-comment">// 挂载后绑定点击监听</span><br>  onMounted(<span class="hljs-function">() =&gt;</span> &#123;<br>    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">&#x27;click&#x27;</span>, updatePosition)<br>  &#125;)<br><br>  <span class="hljs-comment">// 卸载前解绑点击监听</span><br>  onUnmounted(<span class="hljs-function">() =&gt;</span> &#123;<br>    <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">&#x27;click&#x27;</span>, updatePosition)<br>  &#125;)<br><br>  <span class="hljs-keyword">return</span> &#123;x, y&#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<ul>
<li>示例2：使用axios发送异步ajax请求</li>
</ul>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">import</span> &#123; ref &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;vue&#x27;</span><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;axios&#x27;</span><br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useUrlLoader</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">url: <span class="hljs-built_in">string</span></span>) </span>&#123;<br><br>  <span class="hljs-keyword">const</span> result = ref&lt;T | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)<br>  <span class="hljs-keyword">const</span> loading = ref(<span class="hljs-literal">true</span>)<br>  <span class="hljs-keyword">const</span> errorMsg = ref(<span class="hljs-literal">null</span>)<br><br>  axios.get(url)<br>    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> &#123;<br>      loading.value = <span class="hljs-literal">false</span><br>      result.value = response.data<br>    &#125;)<br>    .catch(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> &#123;<br>      loading.value = <span class="hljs-literal">false</span><br>      errorMsg.value = e.message || <span class="hljs-string">&#x27;未知错误&#x27;</span><br>    &#125;)<br><br>  <span class="hljs-keyword">return</span> &#123;<br>    loading,<br>    result,<br>    errorMsg,<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="6-toRef-和-toRefs"><a href="#6-toRef-和-toRefs" class="headerlink" title="6. toRef 和 toRefs"></a>6. toRef 和 toRefs</h4><ul>
<li>toRef 作用：为 reactive 对象上的属性创建 ref。创建的 ref 与源属性同步，修改源属性将更新 ref，修改 ref 也将更新源属性</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> state = reactive(&#123;<br>  <span class="hljs-attr">foo</span>: <span class="hljs-number">1</span>,<br>  <span class="hljs-attr">bar</span>: <span class="hljs-number">2</span><br>&#125;)<br><span class="hljs-keyword">const</span> fooRef = toRef(state, <span class="hljs-string">&#x27;foo&#x27;</span>)<br><br><span class="hljs-comment">// 改变 ref 值，源属性值发生变化</span><br>fooRef.value++<br><span class="hljs-built_in">console</span>.log(state.foo) <span class="hljs-comment">// 2</span><br><br><span class="hljs-comment">// 修改源属性值，ref 值发生变化</span><br>state.foo++<br><span class="hljs-built_in">console</span>.log(fooRef.value) <span class="hljs-comment">// 3</span><br><br><span class="hljs-comment">// 错误示范，fooRef 不会与 state.foo 同步，因为 ref() 接收的是一个纯字符串值</span><br><span class="hljs-comment">// const fooRef = ref(state.foo)</span><br></code></pre></td></tr></table></figure>

<ul>
<li>toRefs 作用：将 reactive 对象转换为普通对象，普通对象的每个属性都是指向原始对象相应属性的 ref。每个单独的 ref 都是使用 toRef 创建的</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useFeatureX</span>(<span class="hljs-params"></span>) </span>&#123;<br>  <span class="hljs-keyword">const</span> state = reactive(&#123;<br>    <span class="hljs-attr">foo</span>: <span class="hljs-number">1</span>,<br>    <span class="hljs-attr">bar</span>: <span class="hljs-number">2</span><br>  &#125;)<br> <br>  <span class="hljs-comment">// 返回时转化为 refs</span><br>  <span class="hljs-keyword">return</span> toRefs(state)<br>&#125;<br><span class="hljs-comment">// 对象解构不会丢失响应式</span><br><span class="hljs-keyword">const</span> &#123; foo, bar &#125; = useFeatureX()<br></code></pre></td></tr></table></figure>

<h3 id="二、其他-Composition-API"><a href="#二、其他-Composition-API" class="headerlink" title="二、其他 Composition API"></a>二、其他 Composition API</h3><h4 id="1-shallowReactive-与-shallowRef"><a href="#1-shallowReactive-与-shallowRef" class="headerlink" title="1. shallowReactive 与 shallowRef"></a>1. shallowReactive 与 shallowRef</h4><ul>
<li>shallowReactive：只处理对象最外层属性的响应式（浅响应式）</li>
<li>shallowRef：只处理基本数据类型的响应式，不进行对象的响应式处理</li>
<li>什么时候使用：<ul>
<li>如果一个对象结构比较深，但只是外层属性发生变化，则使用 shallowReactive</li>
<li>如果一个对象，后续不会修改其属性，而是用新的对象来替换，则使用 shallowRef</li>
</ul>
</li>
</ul>
<h4 id="2-readonly-与-shallowReadonly"><a href="#2-readonly-与-shallowReadonly" class="headerlink" title="2. readonly 与 shallowReadonly"></a>2. readonly 与 shallowReadonly</h4><ul>
<li>readonly：让一个响应式数据变为只读的（深只读）</li>
<li>shallowReadonly：让一个响应式数据变为只读的（浅只读）</li>
<li>使用场景：不希望数据被修改时</li>
</ul>
<h4 id="3-toRaw-与-markRaw"><a href="#3-toRaw-与-markRaw" class="headerlink" title="3. toRaw 与 markRaw"></a>3. toRaw 与 markRaw</h4><ul>
<li><p>toRaw：将一个由 reactive 生成的响应式对象转为普通对象</p>
</li>
<li><p>使用场景：用于读取响应式对象对应的普通对象，对这个普通对象的所有操作，不会引起页面更新</p>
</li>
<li><p>markRaw：标记一个对象，使其永远不会成为响应式对象</p>
</li>
<li><p>使用场景：</p>
<ul>
<li>有些值不应被设置为响应式，例如复杂的第三方类库等</li>
<li>当渲染具有不可变数据源的大列表时，跳过响应式转换可以提高性能</li>
</ul>
</li>
</ul>
<h4 id="4-customRef"><a href="#4-customRef" class="headerlink" title="4. customRef"></a>4. customRef</h4><ul>
<li>作用：创建一个自定义的 ref，并对其依赖项跟踪和更新触发进行显式控制</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">import</span> &#123; ref, customRef &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;vue&#x27;</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;<br>    <span class="hljs-attr">name</span>:<span class="hljs-string">&#x27;Demo&#x27;</span>,<br>    <span class="hljs-function"><span class="hljs-title">setup</span>(<span class="hljs-params"></span>)</span>&#123;<br>        <span class="hljs-comment">// let keyword = ref(&#x27;hello&#x27;) //使用 Vue 准备好的内置 ref</span><br>        <span class="hljs-comment">// 自定义一个 myRef</span><br>        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myRef</span>(<span class="hljs-params">value, delay</span>)</span>&#123;<br>            <span class="hljs-keyword">let</span> timer<br>            <span class="hljs-comment">// 通过 customRef 去实现自定义</span><br>            <span class="hljs-keyword">return</span> customRef(<span class="hljs-function">(<span class="hljs-params">track, trigger</span>)=&gt;</span>&#123;<br>                <span class="hljs-keyword">return</span>&#123;<br>                    <span class="hljs-function"><span class="hljs-title">get</span>(<span class="hljs-params"></span>)</span>&#123;<br>                        track() <span class="hljs-comment">// 告诉 vue 这个 value 值是需要被“追踪”的</span><br>                        <span class="hljs-keyword">return</span> value<br>                    &#125;,<br>                    <span class="hljs-function"><span class="hljs-title">set</span>(<span class="hljs-params">newValue</span>)</span>&#123;<br>                        <span class="hljs-built_in">clearTimeout</span>(timer)<br>                        timer = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">()=&gt;</span>&#123;<br>                            value = newValue<br>                            trigger() <span class="hljs-comment">// 告诉 vue 去更新界面</span><br>                        &#125;,delay)<br>                    &#125;<br>                &#125;<br>            &#125;)<br>        &#125;<br>        <span class="hljs-comment">// 使用自定义的ref</span><br>        <span class="hljs-keyword">let</span> keyword = myRef(<span class="hljs-string">&#x27;hello&#x27;</span>, <span class="hljs-number">500</span>) <br>        <span class="hljs-keyword">return</span> &#123;<br>            keyword<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="5-provide-与-inject"><a href="#5-provide-与-inject" class="headerlink" title="5. provide 与 inject"></a>5. provide 与 inject</h4><ul>
<li>作用：实现祖与后代组件之间的通信。父组件有一个 provide 选项来提供数据，后代组件有一个 inject 选项来使用这些数据</li>
</ul>
<p><img src="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/provide%E5%92%8Cinject.png" srcset="/img/loading.gif" lazyload alt="provide和inject"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 祖组件</span><br><span class="hljs-function"><span class="hljs-title">setup</span>(<span class="hljs-params"></span>)</span> &#123;<br>    <span class="hljs-keyword">let</span> car = reactive(&#123;<span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;奔驰&#x27;</span>, <span class="hljs-attr">price</span>: <span class="hljs-string">&#x27;40万&#x27;</span>&#125;)<br>    provide(<span class="hljs-string">&#x27;car&#x27;</span>, car)<br>&#125;<br><br><span class="hljs-comment">// 后代组件</span><br><span class="hljs-function"><span class="hljs-title">setup</span>(<span class="hljs-params"></span>)</span> &#123;<br>    <span class="hljs-keyword">const</span> car = inject(<span class="hljs-string">&#x27;car&#x27;</span>)<br>    <span class="hljs-keyword">return</span> &#123; car &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="6-响应式数据的判断"><a href="#6-响应式数据的判断" class="headerlink" title="6. 响应式数据的判断"></a>6. 响应式数据的判断</h4><ul>
<li>isRef：检查一个值是否为 ref 对象</li>
<li>isReactive：检查一个对象是否是由 reactive 创建的响应式代理</li>
<li>isReadonly：检查一个对象是否是由 readonly 创建的只读代理</li>
<li>isProxy：检查一个对象是否是由 reactive 或者 readonly 方法创建的代理</li>
</ul>
<h3 id="三、新组件"><a href="#三、新组件" class="headerlink" title="三、新组件"></a>三、新组件</h3><h4 id="1-Fragment（片段）"><a href="#1-Fragment（片段）" class="headerlink" title="1. Fragment（片段）"></a>1. Fragment（片段）</h4><ul>
<li>在 vue2 中：组件必须有一个根标签</li>
<li>在 vue3 中：组件可以没有根标签，内部会将多个标签包含在一个 Fragment 虚拟元素中</li>
<li>好处：减少标签层级，减小内存占用</li>
</ul>
<h4 id="2-Teleport（瞬移）"><a href="#2-Teleport（瞬移）" class="headerlink" title="2. Teleport（瞬移）"></a>2. Teleport（瞬移）</h4><ul>
<li>Teleport 是一种能够将组件的 html 结构移动到指定位置的技术</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- to 目标需要一个 CSS 选择器字符串或一个实际的 DOM 节点 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">teleport</span> <span class="hljs-attr">to</span>=<span class="hljs-string">&quot;body&quot;</span>&gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">&quot;isShow&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;mask&quot;</span>&gt;</span><br>		<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;dialog&quot;</span>&gt;</span><br>			<span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>我是一个弹窗<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br>			<span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">&quot;isShow = false&quot;</span>&gt;</span>关闭弹窗<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br>		<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>	<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">teleport</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h4 id="3-Suspense（不确定的）"><a href="#3-Suspense（不确定的）" class="headerlink" title="3. Suspense（不确定的）"></a>3. Suspense（不确定的）</h4><ul>
<li>作用：等待异步组件时渲染一些额外内容，让应用有更好的用户体验</li>
<li>使用步骤：</li>
</ul>
<ol>
<li>异步引入组件</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">import</span> &#123; defineAsyncComponent &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;vue&#x27;</span><br><span class="hljs-keyword">const</span> Child = defineAsyncComponent(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&#x27;./components/Child.vue&#x27;</span>))<br></code></pre></td></tr></table></figure>

<ol start="2">
<li>使用 Suspense 包裹组件，并配置好 default 和 fallback</li>
</ol>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;app&quot;</span>&gt;</span><br>		<span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>我是App组件<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br>		<span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span>&gt;</span><br>			<span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-slot:default</span>&gt;</span><br>				<span class="hljs-tag">&lt;<span class="hljs-name">Child</span>/&gt;</span><br>			<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span><br>			<span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-slot:fallback</span>&gt;</span><br>				<span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>加载中.....<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br>			<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span><br>		<span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span><br>	<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h3 id="四、其他"><a href="#四、其他" class="headerlink" title="四、其他"></a>四、其他</h3><h4 id="1-全局-API-转移"><a href="#1-全局-API-转移" class="headerlink" title="1. 全局 API 转移"></a>1. 全局 API 转移</h4><ul>
<li>vue3 中将全局 API，即 Vue.xxx 调整到应用实例 app 上</li>
</ul>
<table>
<thead>
<tr>
<th>2.x 全局 API（Vue）</th>
<th>3.x 实例 API (app)</th>
</tr>
</thead>
<tbody><tr>
<td>Vue.config.xxxx</td>
<td>app.config.xxxx</td>
</tr>
<tr>
<td>Vue.config.productionTip</td>
<td>移除</td>
</tr>
<tr>
<td>Vue.component</td>
<td>app.component</td>
</tr>
<tr>
<td>Vue.directive</td>
<td>app.directive</td>
</tr>
<tr>
<td>Vue.mixin</td>
<td>app.mixin</td>
</tr>
<tr>
<td>Vue.use</td>
<td>app.use</td>
</tr>
<tr>
<td>Vue.prototype</td>
<td>app.config.globalProperties</td>
</tr>
</tbody></table>
<h4 id="2-自定义指令"><a href="#2-自定义指令" class="headerlink" title="2. 自定义指令"></a>2. 自定义指令</h4><p>vue2 自定义指令钩子：</p>
<ul>
<li>bind：只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。</li>
<li>inserted：被绑定元素插入父节点时调用 (仅保证父节点存在，但不一定已被插入文档中)。</li>
<li>update：所在组件的 VNode 更新时调用，但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变，也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。</li>
<li>componentUpdated：指令所在组件的 VNode 及其子 VNode 全部更新后调用。</li>
<li>unbind：只调用一次，指令与元素解绑时调用。</li>
</ul>
<p><strong>vue2和vue3自定义指令钩子对比：</strong><br><img src="https://gitee.com/huqian025/my-images/raw/master/vue/vue3%E6%96%B0%E7%89%B9%E6%80%A7/vue2%E5%92%8Cvue3%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%E9%92%A9%E5%AD%90%E5%AF%B9%E6%AF%94.png" srcset="/img/loading.gif" lazyload alt="vue2和vue3自定义指令钩子对比"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// vue2 注册一个全局自定义指令 v-focus</span><br>Vue.directive(<span class="hljs-string">&#x27;focus&#x27;</span>, &#123; <br>    <span class="hljs-comment">// 当被绑定的元素插入到 DOM 中时</span><br>    <span class="hljs-attr">inserted</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>&#123; <br>        <span class="hljs-comment">// 聚焦元素 </span><br>        el.focus() <br>    &#125; <br>&#125;)<br><br><span class="hljs-comment">// vue3 注册一个全局自定义指令 v-focus</span><br><span class="hljs-keyword">const</span> &#123; createApp &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;vue&quot;</span><br><span class="hljs-keyword">const</span> app = createApp(&#123;&#125;) <br>app.directive(<span class="hljs-string">&#x27;focus&#x27;</span>, &#123; <br>    <span class="hljs-function"><span class="hljs-title">mounted</span>(<span class="hljs-params">el</span>)</span> &#123; <br>        el.focus()<br>    &#125; <br>&#125;)<br></code></pre></td></tr></table></figure>

<h4 id="3-v-model"><a href="#3-v-model" class="headerlink" title="3. v-model"></a>3. v-model</h4><ul>
<li>非兼容变更：用于自定义组件时，v-model 的 prop 和事件默认名称已更改<ul>
<li>prop: value -&gt; modelValue</li>
<li>事件: input -&gt; update:modelValue</li>
</ul>
</li>
<li>非兼容变更：v-bind 的 .sync 修饰符和组件的 model 选项已移除，可在 v-model 上加一个参数代替</li>
<li>新增：可以在同一组件上使用多个 v-model 绑定</li>
<li>新增：可以自定义 v-model 修饰符</li>
</ul>
<h5 id="3-1-vue2-语法"><a href="#3-1-vue2-语法" class="headerlink" title="3.1 vue2 语法"></a>3.1 vue2 语法</h5><p>vue2 中，在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> /&gt;</span><br><span class="hljs-comment">&lt;!-- 等价于 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:value</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> @<span class="hljs-attr">input</span>=<span class="hljs-string">&quot;pageTitle = $event&quot;</span> /&gt;</span><br></code></pre></td></tr></table></figure>

<h6 id="3-1-1-model-选项配置修改双向绑定"><a href="#3-1-1-model-选项配置修改双向绑定" class="headerlink" title="3.1.1 model 选项配置修改双向绑定"></a>3.1.1 model 选项配置修改双向绑定</h6><p>如果想要更改 prop 或事件名称，则需要在 ChildComponent 组件中添加 model 选项</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- ParentComponent.vue --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> /&gt;</span><br><span class="hljs-comment">&lt;!-- 等价于 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:title</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> @<span class="hljs-attr">change</span>=<span class="hljs-string">&quot;pageTitle = $event&quot;</span> /&gt;</span><br></code></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// ChildComponent.vue</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;<br>  <span class="hljs-attr">model</span>: &#123;<br>    <span class="hljs-attr">prop</span>: <span class="hljs-string">&#x27;title&#x27;</span>,<br>    <span class="hljs-attr">event</span>: <span class="hljs-string">&#x27;change&#x27;</span><br>  &#125;,<br>  <span class="hljs-attr">props</span>: &#123;<br>    <span class="hljs-comment">// 这将允许 `value` 属性用于其他用途</span><br>    <span class="hljs-attr">value</span>: <span class="hljs-built_in">String</span>,<br>    <span class="hljs-comment">// 使用 `title` 代替 `value` 作为 model 的 prop</span><br>    <span class="hljs-attr">title</span>: &#123;<br>      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,<br>      <span class="hljs-attr">default</span>: <span class="hljs-string">&#x27;Default title&#x27;</span><br>    &#125;<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h6 id="3-1-2-v-bind-sync-修改双向绑定（vue3-中已移除）"><a href="#3-1-2-v-bind-sync-修改双向绑定（vue3-中已移除）" class="headerlink" title="3.1.2 v-bind.sync 修改双向绑定（vue3 中已移除）"></a>3.1.2 v-bind.sync 修改双向绑定（vue3 中已移除）</h6><p>在某些情况下，我们可能需要对某一个 prop 进行“双向绑定”，可以在子组件中抛出 update:myPropName 事件，父组件使用 :myPropName.sync 实现对 myPropName 属性的双向绑定</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// ChildComponent.vue</span><br><span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">&#x27;update:title&#x27;</span>, newValue)<br></code></pre></td></tr></table></figure>

<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-comment">&lt;!-- ParentComponent.vue --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:title</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> @<span class="hljs-attr">update:title</span>=<span class="hljs-string">&quot;pageTitle = $event&quot;</span> /&gt;</span><br><span class="hljs-comment">&lt;!-- 等价于 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:title.sync</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> /&gt;</span><br></code></pre></td></tr></table></figure>

<h5 id="3-2-vue3-语法"><a href="#3-2-vue3-语法" class="headerlink" title="3.2 vue3 语法"></a>3.2 vue3 语法</h5><p>在 vue3 中，自定义组件上的 v-model 相当于传递了 modelValue prop 并接收抛出的 update:modelValue 事件</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> /&gt;</span><br><span class="hljs-comment">&lt;!-- 等价于 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:modelValue</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> @<span class="hljs-attr">update:modelValue</span>=<span class="hljs-string">&quot;pageTitle = $event&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>如果需要更改 model 名称，可以为 v-model 传递一个参数，作为组件内的 model 选项代替</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">v-model:title</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> /&gt;</span><br><span class="hljs-comment">&lt;!-- 等价于 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">:title</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> @<span class="hljs-attr">update:title</span>=<span class="hljs-string">&quot;pageTitle = $event&quot;</span> /&gt;</span><br></code></pre></td></tr></table></figure>

<p>这也可以作为 .sync 修饰符的替代，而且允许我们在自定义组件上使用多个 v-model</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">v-model:title</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> <span class="hljs-attr">v-model:content</span>=<span class="hljs-string">&quot;pageContent&quot;</span> /&gt;</span><br><span class="hljs-comment">&lt;!-- 等价于 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> </span><br><span class="hljs-tag">    <span class="hljs-attr">:title</span>=<span class="hljs-string">&quot;pageTitle&quot;</span> @<span class="hljs-attr">update:title</span>=<span class="hljs-string">&quot;pageTitle = $event&quot;</span></span><br><span class="hljs-tag">    <span class="hljs-attr">:content</span>=<span class="hljs-string">&quot;pageContent&quot;</span> @<span class="hljs-attr">update:content</span>=<span class="hljs-string">&quot;pageContent = $event&quot;</span> /&gt;</span><br></code></pre></td></tr></table></figure>

<h4 id="4-异步组件"><a href="#4-异步组件" class="headerlink" title="4. 异步组件"></a>4. 异步组件</h4><p>Vue3 中 使用 defineAsyncComponent 定义异步组件，配置选项 component 替换为 loader，loader 函数本身不再接收 resolve 和 reject 参数，且必须返回一个 Promise，用法如下：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <br>    <span class="hljs-comment">&lt;!-- 异步组件的使用 --&gt;</span> <br>    <span class="hljs-tag">&lt;<span class="hljs-name">AsyncPage</span> /&gt;</span> <br>    <span class="hljs-tag">&lt;<span class="hljs-name">AsyncPageWithOptions</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">tempate</span>&gt;</span><br></code></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">import</span> &#123; defineAsyncComponent &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">&quot;vue&quot;</span>; <br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123; <br>    <span class="hljs-attr">components</span>: &#123;<br>        <span class="hljs-comment">// 无配置项异步组件 </span><br>        <span class="hljs-attr">AsyncPage</span>: defineAsyncComponent(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&quot;./NextPage.vue&quot;</span>)),<br>        <br>        <span class="hljs-comment">// 有配置项异步组件 </span><br>        <span class="hljs-attr">AsyncPageWithOptions</span>: defineAsyncComponent(&#123; <br>            <span class="hljs-attr">loader</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&quot;./NextPage.vue&quot;</span>), <br>            <span class="hljs-attr">delay</span>: <span class="hljs-number">200</span>, <br>            <span class="hljs-attr">timeout</span>: <span class="hljs-number">3000</span>, <br>            <span class="hljs-attr">errorComponent</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&quot;./ErrorComponent.vue&quot;</span>), <br>            <span class="hljs-attr">loadingComponent</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&quot;./LoadingComponent.vue&quot;</span>)<br>        &#125;) <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="5-其他改变"><a href="#5-其他改变" class="headerlink" title="5. 其他改变"></a>5. 其他改变</h4><ul>
<li>data 选项应始终被声明为一个函数</li>
<li>过渡类名更改：</li>
</ul>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-comment">/* vue2 写法 */</span><br><span class="hljs-selector-class">.v-enter</span>,<br><span class="hljs-selector-class">.v-leave-to</span> &#123;<br>    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;<br>&#125;<br><span class="hljs-selector-class">.v-leave</span>,<br><span class="hljs-selector-class">.v-enter-to</span> &#123;<br>    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;<br>&#125;<br><br><span class="hljs-comment">/* vue3 写法 */</span><br><span class="hljs-selector-class">.v-enter-from</span>,<br><span class="hljs-selector-class">.v-leave-to</span> &#123;<br>    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;<br>&#125;<br><span class="hljs-selector-class">.v-leave-from</span>,<br><span class="hljs-selector-class">.v-enter-to</span> &#123;<br>    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<ul>
<li>移除 keyCode 作为 v-on 的修饰符，同时也不再支持 config.keyCodes</li>
<li>移除 v-on.native 修饰符</li>
<li>移除过滤器（filter）</li>
<li>v-if 优先 v-for 解析</li>
</ul>
<blockquote>
<p>参考文档：<br><a target="_blank" rel="noopener" href="https://juejin.cn/post/6940454764421316644">掘金：Vue3.0 新特性以及使用经验总结</a><br><a target="_blank" rel="noopener" href="https://vuejs.org/api/reactivity-utilities.html#toref">Vue3 API toRef</a><br><a target="_blank" rel="noopener" href="https://v3.cn.vuejs.org/guide/migration/v-model.html">Vue2 迁移 Vue3 文档 v-model</a></p>
</blockquote>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/vue/">vue</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/vue3/">vue3</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/02/24/this%E6%8C%87%E5%90%91/">
                        <span class="hidden-mobile">this指向</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
  </div>
  

  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  






  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
        typing(title);
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
